#ifndef persistentfoodlist_h
#define persistentfoodlist_h

#include <vector>
#include <deque>
#include <fstream>
#include <iostream>
#include <string>
#include <sstream>
#include <iterator>
#include <map>
#include <exception>

#include "../FoodObjects/Food.h"
#include "../Recipe.h"
#include "juce_amalgamated.h"

using namespace std;

class Util {
public:
	static void trimAndLower(string& s) {
		if (s.size() > 2)
			s = s.substr(1, s.size() - 2);
		else
			s = "";

		for (int i = 0; i < (int)s.size(); i++) {
			if (i > 0 && s[i - 1] != ' ' && s[i] >= 'A' && s[i] <= 'Z')
				s[i] = tolower(s[i]);
		}
	}
};

class FoodName {
public:
	int id;
	int groupID;

	string abbrFoodnameE;
	string abbrFoodnameF;
	string foodnameE;
	string foodnameF;

	FoodName() :
		id(0), groupID(0), abbrFoodnameE(""), abbrFoodnameF(""), foodnameE(""), foodnameF("") {

	}

	FoodName(int a, int b, string afe, string aff, string fe, string ff) :
		id(a), groupID(b), abbrFoodnameE(afe), abbrFoodnameF(aff), foodnameE(fe), foodnameF(ff) {
		Util::trimAndLower(foodnameE);
		Util::trimAndLower(foodnameF);
	}

	void operator=(const FoodName& other) {
		id = other.id;
		groupID = other.groupID;
		abbrFoodnameE = other.abbrFoodnameE;
		abbrFoodnameF = other.abbrFoodnameF;
		foodnameE = other.foodnameE;
		foodnameF = other.foodnameF;
	}

	friend ostream& operator<<(ostream& stream, FoodName foodname);
};

class FoodGroupName {
public:
	int id;
	string groupnameE;
	string groupnameF;

	FoodGroupName() :
		id(0), groupnameE(""), groupnameF("") {
	}
	FoodGroupName(int a, string gne, string gnf) :
		id(a), groupnameE(gne), groupnameF(gnf) {

	}

	void operator=(const FoodGroupName& other) {
		id = other.id;
		groupnameE = other.groupnameE;
		groupnameF = other.groupnameF;
	}
};

class NutritionAmount {
public:
	int foodID;
	int ntID;
	float amount;

	void operator=(const NutritionAmount& other) {
		foodID = other.foodID;
		ntID = other.ntID;
		amount = other.amount;
	}
};

class ConversionFactor {
public:
	int fid;
	int mid;
	float factor;
	ConversionFactor() :
		fid(0), mid(0), factor(0) {
	}
	ConversionFactor(int fid, int mid, float factor) :
		fid(fid), mid(mid), factor(factor) {

	}
	void operator=(const ConversionFactor& other) {
		fid = other.fid;
		mid = other.mid;
		factor = other.factor;
	}
};

class Measure {
private:
public:
	int id;
	String desc;

	Measure() :
		id(0), desc(String::empty) {
	}

	Measure(int id, String desc) :
		id(id), desc(desc) {
		this->desc = this->desc.substring(1, this->desc.length() - 1);
	}

	void operator=(const Measure& other) {
		this->id = other.id;
		this->desc = other.desc;
	}
};

class NutritionName {
public:
	int id;
	string symbol;
	string unit;
	string nameE;
	string nameF;
	NutritionName() :
		id(0), symbol(""), unit(""), nameE(""), nameF("") {
	}
	NutritionName(int a, string b, string c, string d, string e) :
		id(a), symbol(b), unit(c), nameE(d), nameF(e) {
		Util::trimAndLower(unit);
		Util::trimAndLower(nameE);
		Util::trimAndLower(nameF);
		Util::trimAndLower(symbol);
	}

	void operator=(const NutritionName& other) {
		id = other.id;
		symbol = other.symbol;
		unit = other.unit;
		nameE = other.nameE;
		nameF = other.nameF;
	}
};

class PersistentFoodList {
private:
	deque<Eatable> foods;
	map<int, Eatable*> foodMap;
	deque<Eatable> meals;
	map<int, Recipe> recipes;

	PersistentFoodList();
	~PersistentFoodList();
	void read();
public:
	static PersistentFoodList& instance() {
		static PersistentFoodList foodList;
		cout << &foodList << endl;
		return foodList;
	}

	deque<Eatable>& getFoods() {
		return foods;
	}

	map<int, Eatable*>& getFoodMap() {
		return foodMap;
	}

	deque<Eatable>& getMeals() {
		return meals;
	}

	map<int, Recipe>& getRecipes() {
		return recipes;
	}
};

#endif
